﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Xml;
using VmcRemote.Common.Interfaces;
using System.Reflection;
using System.Resources;

namespace VmcRemote.Common
{
    public class RemoteSettings
    {
        public Type ConnectionType { get; set; }
        public Type ServerType { get; set; }
        public ResourceManager ResourceManager { get; set; }
        public string Host { get; set; }
        public int Port { get; set; }

        public IConnection CreateConnection()
        {
            System.Reflection.ConstructorInfo constructor = ConnectionType.GetConstructor(new Type[] { typeof(string), typeof(int) });
            IConnection connection = constructor.Invoke(new object[] { Host, Port }) as IConnection;
            return connection;
        }

        public IMediaCenter CreateServer()
        {
            System.Reflection.ConstructorInfo constructor = ServerType.GetConstructor(new Type[] { });
            IMediaCenter server = constructor.Invoke(new object[] { }) as IMediaCenter;
            server.ConfigurationXml = ResourceManager.GetString(ServerType.Name);
            return server;
        }

        public static Type DefaultConnectionType
        {
            get
            {
#if TEST
                return typeof(DummyConnection);
#else
                return typeof(TcpConnection);
#endif
            }
        }

        public static List<Type> ConnectionTypes
        {
            get
            {
                return new List<Type>
                {
#if DEBUG
                    typeof(DummyConnection),
#endif
                    typeof(TcpConnection)
                };
            }
        }

        public static List<Type> ServerTypes
        {
            get
            {
                return new List<Type>
                {
                    typeof(MceController),
                    typeof(VmcController)
                };
            }
        }

        public static RemoteSettings Load()
        {
            string filename = Path.Combine(
                Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase),
                "settings.xml"
                );

            RemoteSettings loadedSettings = null;
            if (string.IsNullOrEmpty(filename)) throw new ArgumentNullException("filename");
            if (File.Exists(filename))
            {
                using (XmlReader reader = XmlReader.Create(filename))
                {
                    loadedSettings = Load(reader);
                }
            }
            return loadedSettings;
        }

        private static RemoteSettings Load(XmlReader reader)
        {
            if (reader == null) throw new ArgumentNullException("reader");

            RemoteSettings loadedSettings = null;

            try
            {
                XDocument settingsDoc = XDocument.Load(reader);
                var settings = from connectionElement in settingsDoc.Descendants("connection")
                               select new RemoteSettings
                               {
                                   Host = (string)connectionElement.Attribute("host"),
                                   Port = (int)connectionElement.Attribute("port"),
                                   ConnectionType = Type.GetType((string)connectionElement.Attribute("type"), false),
                                   ServerType = Type.GetType((string)connectionElement.Attribute("server"), false)
                               };

                if (settings != null && settings.Count() > 0)
                {
                    foreach (RemoteSettings currentSettings in settings)
                    {
                        if (Validate(currentSettings))
                            loadedSettings = currentSettings;
                    }
                }
            }
            catch { }

            return loadedSettings;
        }

        private static bool Validate(RemoteSettings settings)
        {
            return !string.IsNullOrEmpty(settings.Host)
                && settings.Port > 0
                && settings.ConnectionType.GetInterfaces().Contains(typeof(IConnection));
        }

        public void Save()
        {
            string filename = Path.Combine(
                Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase),
                "settings.xml"
                );

            using (XmlTextWriter writer = new XmlTextWriter(filename, Encoding.UTF8))
                Save(writer);
        }

        private void Save(XmlTextWriter writer)
        {
            XDocument doc = new XDocument();
            doc.Add(
                new XElement("remoteSettings",
                    new XElement("connection",
                        new XAttribute("host", this.Host),
                        new XAttribute("port", this.Port),
                        new XAttribute("type", this.ConnectionType),
                        new XAttribute("server", this.ServerType)
                        )
                    )
                );
            doc.WriteTo(writer);
            writer.Flush();
        }

        public bool Validate()
        {
            IConnection connection = null;
            bool connected = false;
            try
            {
                using (connection = CreateConnection())
                    connected = connection.Status == ConnectionStatus.Open;
            }
            catch (Exception) { }
            return connected;
        }

        private static string GetServerConfigFileName(Type serverType)
        {
            return Path.Combine(
                Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase),
                serverType.Name + ".config"
                );
        }
    }
}
